using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Runtime.Serialization;
using System.ComponentModel;
using System.Collections.ObjectModel;
using MReviewerClient.MReviewerSvc;
using MReviewerClient.Providers;

namespace MReviewerClient.Models
{
    /// <summary>
    /// The model of Review
    /// </summary>
    public class ReviewModel
    {
        #region Fields

        /// <summary>
        /// The collection of Review
        /// </summary>
        public ObservableCollection<ReviewDTO> Reviews;

        /// <summary>
        /// The average rating
        /// </summary>
        public double AverageRating
        {
            get
            {
                if (this.Reviews == null)
                    return 0;

                double totalRating = 0;
                foreach (ReviewDTO item in this.Reviews)
                    totalRating += item.OverallRating;

                if (totalRating > 0)
                    return totalRating / this.Reviews.Count;
                return 0;
            }
        }

        /// <summary>
        /// The number of reviewer
        /// </summary>
        public int NumReviewer
        {
            get
            {
                if (this.Reviews != null)
                    return this.Reviews.Count;
                return 0;
            }
        }

        /// <summary>
        /// The object for synchronization
        /// </summary>
        private static object syncLock = new object();

        /// <summary>
        /// The instance of ReviewModel
        /// </summary>
        private static ReviewModel instance;

        /// <summary>
        /// The singleton instance
        /// </summary>
        public static ReviewModel Instance
        {
            get
            {
                lock (syncLock)
                {
                    if (instance == null)
                        instance = new ReviewModel();
                    return instance;
                }
            }
        }

        /// <summary>
        /// The result of inserting
        /// </summary>
        public bool InsertResult { get; set; }

        #endregion

        #region Methods

        /// <summary>
        /// Select all of Review of sepecified establishment from the service
        /// </summary>
        /// <param name="idEstablishment">
        /// The id of specified establishment
        /// </param>
        /// <param name="actionUpdateContext">
        /// This action will be executed when the operation for interacting to service is completely
        /// </param>
        public void SelectByEstablishment(string idEstablishment, Action actionUpdateContext)
        {
            // The action is invoked when the operation is complete
            EventHandler<Review_SelectByEstablismentCompletedEventArgs> handler = null;
            handler = (s, e) =>
            {
                this.Reviews = e.Result;
                MReviewerService.Instance.Review_SelectByEstablismentCompleted -= handler;
                actionUpdateContext();
            };
            // Read all of the establishment
            MReviewerService.Instance.Review_SelectByEstablismentCompleted += handler;
            MReviewerService.Instance.Review_SelectByEstablismentAsync(idEstablishment);
        }

        /// <summary>
        /// Insert new review
        /// </summary>
        /// <param name="item">
        /// The review information for inserting
        /// </param>
        /// <param name="actionInformResult">
        /// This action will be executed when the operation for interacting to service is completely
        /// </param>
        public void Insert(ReviewDTO item, Action actionInformResult)
        {
            // The action is invoked when the operation is complete
            EventHandler<Review_InsertCompletedEventArgs> handler = null;
            handler = (s, e) =>
            {
                this.InsertResult = e.Result;
                if (this.InsertResult)
                {
                    this.Reviews.Add(item);
                }
                MReviewerService.Instance.Review_InsertCompleted -= handler;
                actionInformResult();
            };
            MReviewerService.Instance.Review_InsertCompleted += handler;
            MReviewerService.Instance.Review_InsertAsync(item);
        }

        /// <summary>
        /// Select an Review by ID
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ReviewDTO SelectByID(int id)
        {
            return this.Reviews.FirstOrDefault(n => n.ID == id);
        }

        #endregion
    }
}